#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import datetime
import functools


# 装饰器有些java中的面向切面编程思想
def now():
    print(datetime.date.today())


now()  # 2019-02-14
# f = now
# print(now.__name__) # now
# print(f.__name__) # now

'''
    假设我们要增强now()函数的功能，比如，在函数调用前后自动打印日志，
    但又不希望修改now()函数的定义，这种在代码运行期间动态增加功能的
    方式，称之为“装饰器”（Decorator）。
    本质上，decorator就是一个返回函数的高阶函数。所以，我们要定义一
    个能打印日志的decorator
'''


def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)

    return wrapper


# 给now增加装饰器
@log # 相当于执行：now = log(now1)
def now1():
    print(datetime.date.today())


now1()  # call now1(): 2019-02-14


# 带有参数的装饰器
def logwith(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)

        return wrapper

    return decorator


@logwith('execute:')
def now2():
    print(datetime.date.today())


now2()  # execute: now2(): 2019-02-14
print(now2.__name__)  # wrapper  不在是now2了


# now2 = logwith('execute')(now2)

# wrapper.__name__ = now2.__name__


# 案例1：
def metric(fn):
    @functools.wraps(fn)
    def end(*args, **kw):
        btime = time.time()
        tp = fn(*args, **kw)
        etime = time.time()
        print('%s executed in %s ms' % (fn.__name__, etime - btime))
        return tp

    return end


# 测试
@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y


@metric
def slow(x, y, z):
    time.sleep(0.1234)
    return x * y * z


f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
    print('测试失败!')
elif s != 7986:
    print('测试失败!')

print(fast.__name__)
print(slow.__name__)


# 案例2
def exlog(text=''):
    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(*args,**kw):
            print('%sbegin call:' % text)
            rt = fn(*args,**kw)
            print('end call!')
            return rt
        return wrapper
    return decorator

@exlog('excute:')
def sum(x,y):
    return x + y

print(sum(2,3))
